package com.yhy.wxzn.wms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import com.yhy.wxzn.common.enums.*;
import com.yhy.wxzn.common.exception.WmsBusinessException;
import com.yhy.wxzn.common.service.IWmsBusinessService;
import com.yhy.wxzn.common.utils.DateUtil;
import com.yhy.wxzn.common.utils.ObjectFilterHelper;
import com.yhy.wxzn.wcs.device.rgv.enums.NodeStatus;
import com.yhy.wxzn.wcs.device.rgv.enums.NodeType;
import com.yhy.wxzn.wcs.entity.*;
import com.yhy.wxzn.wcs.service.*;
import com.yhy.wxzn.wms.entity.*;
import com.yhy.wxzn.wms.mapper.WmsPickOrderMapper;
import com.yhy.wxzn.wms.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 出库单
 * @Author: jeecg-boot
 * @Date: 2023-11-08
 * @Version: V1.0
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class WmsPickOrderServiceImpl extends ServiceImpl<WmsPickOrderMapper, WmsPickOrder> implements IWmsPickOrderService {

    @Autowired
    private WmsPickOrderMapper pickOrderMapper;
    @Autowired
    private IWmsBusinessService businessService;
    @Autowired
    private IWmsOutboundConfigService outboundConfigService;
    @Autowired
    private IWcsMapInfoService mapInfoService;
    @Autowired
    private IWmsPickDetailService pickDetailService;
    @Autowired
    private IWmsInventoryService inventoryService;
    @Autowired
    private IWmsPickTaskService pickTaskService;
    @Autowired
    private ISysBaseAPI sysBaseAPI;
    @Autowired
    private IWmsBusinessMsgService businessMsgService;

    @Override
    public IPage<WmsPickOrder> pageSelf(Page<WmsPickOrder> page, QueryWrapper<WmsPickOrder> queryWrapper) {
        return pickOrderMapper.pageSelf(page, queryWrapper);
    }

    @Override
    public void addPickOrder(WmsPickOrder pickOrder) {
        String asnCode = businessService.genWmsBusinessCode("PK" + DateUtil.format(new Date(), "YYMMdd"), 8);
        pickOrder.setCode(asnCode);
        if (StringUtils.isEmpty(pickOrder.getOrderDate())) {
            pickOrder.setOrderDate(new Date());
        }
        ObjectFilterHelper.getObjDefault(pickOrder);
        this.save(pickOrder);
    }

    @Override
    public void allocateBatch(String pkIds) {
        List<String> pkList = Arrays.asList(pkIds.split(","));
        StringBuffer msgBuffer = new StringBuffer();
        pkList = filterPickStatus(pkList, "ALLOCATE", Arrays.asList(WmsOrderStatusEnums.XJ.getValue()), Arrays.asList(WmsOrderStatusEnums.XJ.getValue(), WmsOrderStatusEnums.BFFP.getValue()));
        Set<WmsPickOrder> setQueue = new HashSet<>();
        pkList.stream().forEach(a -> {
            WmsPickOrder pickOrder = this.getById(a);
            try {
                if (!setQueue.contains(pickOrder)) {
                    this.allocate(pickOrder);
                }
            } catch (Exception e) {
                setQueue.add(pickOrder);
                msgBuffer.append("单号:【" + pickOrder.getCode() + "】分配失败:" + e.getMessage());
            }
        });
        if (!ObjectUtils.isEmpty(msgBuffer)) {
            //发送处理失败消息
            sendFailMessage(msgBuffer.toString(),"ALLOCATE");
        }
    }

    private void sendFailMessage(String errorMsg,String msgType) {
        //获取当前登录用户
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        MessageDTO msgDto = new MessageDTO();
        msgDto.setFromUser(user.getUsername());
        msgDto.setToUser(user.getUsername());
        msgDto.setContent(errorMsg);
        if("ALLOCATE".equals(msgType)){
            msgDto.setTitle("下架分配失败消息");
        }else{
            msgDto.setTitle("下架分发失败消息");
        }
        sysBaseAPI.sendSysAnnouncement(msgDto);
    }

    private void allocate(WmsPickOrder pickOrder) {
        log.info("================开始分配拣货单：【" + pickOrder.getCode() + "】==========================");
        //查找出库配置
        LambdaQueryWrapper<WmsOutboundConfig> configQuery = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<WcsMapInfo> mapQuery = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<WmsInventory> invQuery = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<WmsPickDetail> detailQuery = new LambdaQueryWrapper<>();
        configQuery.eq(WmsOutboundConfig::getStatus, ValidEnums.ENABLE.getValue());
        configQuery.eq(WmsOutboundConfig::getOrderType, pickOrder.getOrderType());
        WmsOutboundConfig outboundConfig = outboundConfigService.getOne(configQuery);
        if (!ObjectUtils.isEmpty(outboundConfig)) {
            if (!StringUtils.isEmpty(outboundConfig.getLimitXpos()) && outboundConfig.getLimitXpos() > 0) {
                mapQuery.lt(WcsMapInfo::getX, outboundConfig.getLimitXpos());
            }
            if (!StringUtils.isEmpty(outboundConfig.getLimitYpos()) && outboundConfig.getLimitYpos() > 0) {
                mapQuery.lt(WcsMapInfo::getY, outboundConfig.getLimitYpos());
            }
            if (!StringUtils.isEmpty(outboundConfig.getLimitLayer()) && outboundConfig.getLimitLayer() > 0) {
                mapQuery.lt(WcsMapInfo::getZ, outboundConfig.getLimitLayer());
            }
        }
        mapQuery.eq(WcsMapInfo::getNodeType, NodeType.P.getCodeNum());
        mapQuery.eq(WcsMapInfo::getStatus, ValidEnums.ENABLE.getValue());
        mapQuery.eq(WcsMapInfo::getNodeStatus, NodeStatus.N.toString());
        mapQuery.orderByAsc(WcsMapInfo::getCoord);
        List<WcsMapInfo> coords = mapInfoService.list(mapQuery);
        detailQuery.eq(WmsPickDetail::getPickId, pickOrder.getId());
        List<WmsPickDetail> pickDetails = pickDetailService.list(detailQuery);
        if (CollectionUtils.isEmpty(pickDetails) || CollectionUtils.isEmpty(coords)) {
            return;
        }
        List<String> locIds = coords.stream().map(WcsMapInfo::getId).collect(Collectors.toList());
        //匹配库存
        for (WmsPickDetail pickDetail : pickDetails) {
            invQuery.eq(WmsInventory::getItemId, pickDetail.getItemId());
            if (!StringUtils.isEmpty(pickDetail.getLot01())) {
                invQuery.eq(WmsInventory::getLot01, pickDetail.getLot01());
            }
            if (!StringUtils.isEmpty(pickDetail.getLot02())) {
                invQuery.eq(WmsInventory::getLot02, pickDetail.getLot02());
            }
            if (!StringUtils.isEmpty(pickDetail.getLot03())) {
                invQuery.eq(WmsInventory::getLot03, pickDetail.getLot03());
            }
            if (!StringUtils.isEmpty(pickDetail.getLot04())) {
                invQuery.eq(WmsInventory::getLot04, pickDetail.getLot04());
            }
            if (!StringUtils.isEmpty(pickDetail.getLot05())) {
                invQuery.eq(WmsInventory::getLot05, pickDetail.getLot05());
            }
            if (!StringUtils.isEmpty(pickDetail.getLot06())) {
                invQuery.eq(WmsInventory::getLot06, pickDetail.getLot06());
            }
            if (!StringUtils.isEmpty(pickDetail.getLot07())) {
                invQuery.eq(WmsInventory::getLot07, pickDetail.getLot07());
            }
            if (!CollectionUtils.isEmpty(locIds)) {
                invQuery.in(WmsInventory::getLocationId, locIds);
            }
            invQuery.gt(WmsInventory::getInvQty, BigDecimal.ZERO);
            List<WmsInventory> invs = inventoryService.list(invQuery);
            if (CollectionUtils.isEmpty(invs)) {
                throw new WmsBusinessException("单号：【" + pickOrder.getCode() + "】未匹配到库存信息!");
            }
            invs = allocateDetail(pickDetail, invs);
            genPickTask(pickOrder, invs);
            pickDetailService.refreshPickOrderStatus(pickOrder.getId());
        }
    }

    private void genPickTask(WmsPickOrder pickOrder, List<WmsInventory> invs) {
        //库存按托盘号分组
        Map<String, List<WmsInventory>> groupInv = invs.stream().collect(Collectors.groupingBy(WmsInventory::getPalletNo));
        for (String pelletNo : groupInv.keySet()) {
            List<WmsInventory> invList = groupInv.get(pelletNo);
            BigDecimal taskQty = invList.stream().map(WmsInventory::getInvQty).reduce(BigDecimal.ZERO, BigDecimal::add);
            WcsMapInfo sourceLoc = mapInfoService.getById(invList.get(0).getLocationId());
            WcsMapInfo targetLoc = mapInfoService.getById(pickOrder.getShipLocationId());
            WmsPickTask pickTask = new WmsPickTask();
            String taskNo = businessService.genWmsBusinessCode("PT" + DateUtil.format(new Date(), "YYMMdd"), 8);
            pickTask.setTaskNo(taskNo);
            pickTask.setPickCode(pickOrder.getCode());
            pickTask.setSource(sourceLoc.getCoord());
            pickTask.setTarget(targetLoc.getCoord());
            pickTask.setTaskQty(taskQty);
            ObjectFilterHelper.getObjDefault(pickOrder);
            pickTaskService.save(pickTask);
        }
    }

    private List<WmsInventory> allocateDetail(WmsPickDetail pickDetail, List<WmsInventory> invs) {
        List<WmsInventory> result = new ArrayList<>();
        //需求数量
        BigDecimal demonQty = pickDetail.getDemonQty();
        for (WmsInventory inv : invs) {
            if (demonQty.compareTo(BigDecimal.ZERO) > 0) {
                //库存数量大于需求量
                if (inv.getInvQty().compareTo(demonQty) > 0 && !inv.isAllocate()) {
                    BigDecimal allocateQty = inv.getInvQty().subtract(demonQty);
                    inv.setInvQty(allocateQty);
                    pickDetail.setAllocateQty(pickDetail.getDemonQty());
                    demonQty = BigDecimal.ZERO;
                    result.add(inv);
                } else {
                    if (!inv.isAllocate()) {
                        demonQty = demonQty.subtract(inv.getInvQty());
                        pickDetail.setAllocateQty(inv.getInvQty());
                        inv.setInvQty(BigDecimal.ZERO);
                        inv.setAllocate(Boolean.TRUE);
                        result.add(inv);
                    }
                }
            }
            inventoryService.saveOrUpdate(inv);
            pickDetailService.saveOrUpdate(pickDetail);
        }
        return result;
    }

    private List<String> filterPickStatus(List<String> pkIds, String searchType, List<Integer> pickStatus, List<Integer> otherStatus) {
        StringBuffer sql = new StringBuffer();
        if ("ALLOCATE".equals(searchType)) {
            sql.append("select id from wms_pick_order where order_status in {0} and allocate_status in {1} and id in {2}");
        } else {
            sql.append("select id from wms_pick_order where order_status in {0} and allocate_status in {1} and id in {2}");
        }
        List<Map<String, Object>> mapList = SqlRunner.db().selectList(sql.toString(), pickStatus, otherStatus, pkIds);
        if (CollectionUtils.isEmpty(mapList)) {
            throw new WmsBusinessException("未匹配到符合条件的拣货单!");
        }
        List<String> result = mapList.stream().map(m -> m.get("id") + "").collect(Collectors.toList());
        return result;
    }

    @Override
    public void dispatchBatch(String pkIds) {
        List<String> pickList = Arrays.asList(pkIds.split(","));
        StringBuffer msgBuffer = new StringBuffer();
        pickList = filterPickStatus(pickList, "DISPATCH", Arrays.asList(WmsOrderStatusEnums.XJ.getValue()), Arrays.asList(WmsOrderStatusEnums.BFFP.getValue(), WmsOrderStatusEnums.FPWC.getValue()));
        Set<WmsPickOrder> setQueue = new HashSet<>();
        pickList.stream().forEach(a -> {
            WmsPickOrder pickOrder = this.getById(a);
            try {
                if (!setQueue.contains(pickOrder)) {
                    this.dispatch(pickOrder);
                }
            } catch (Exception e) {
                setQueue.add(pickOrder);
                msgBuffer.append("单号:【" + pickOrder.getCode() + "】分发失败:" + e.getMessage());
            }
        });
        if (!ObjectUtils.isEmpty(msgBuffer)) {
            //发送处理失败消息
            sendFailMessage(msgBuffer.toString(),"DISPATCH");
        }
    }

    private void dispatch(WmsPickOrder pickOrder) {
        log.info("================开始分发拣货单：【" + pickOrder.getCode() + "】==========================");
        businessMsgService.dispatchGetDownTask(pickOrder);
    }


}
